package com.ruoyi.web.controller.wx.controller;

import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.module.domain.Goods;
import com.ruoyi.module.domain.Order;
import com.ruoyi.module.domain.OrderGoods;
import com.ruoyi.module.service.IFundDetailsService;
import com.ruoyi.module.service.IGoodsService;
import com.ruoyi.module.service.IOrderService;
import com.ruoyi.system.service.ISysUserService;
import com.ruoyi.web.controller.wx.config.WechatPayConfig;
import com.ruoyi.web.controller.wx.request.HttpUtils;
import com.ruoyi.web.controller.wx.request.WechatPayValidator;
import com.wechat.pay.contrib.apache.httpclient.auth.Verifier;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.*;
import java.util.*;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author kaur
 */
@Slf4j
@RestController
@RequestMapping("/common/notify")
@Api(tags = "商户-普通支付-回调接口(API3)")
public class CommonNotifyController {

    @Autowired
    private WechatPayConfig wechatPayConfig;
    @Autowired
    private Verifier verifier;
    @Autowired
    private IOrderService orderService;
    @Autowired
    private IFundDetailsService fundDetailsService;
    @Autowired
    private IGoodsService goodsService;
    @Autowired
    private ISysUserService userService;
    @Autowired
    private CommonPayController commonPayController;

    private final ReentrantLock lock = new ReentrantLock();

    @PostMapping("/jsapi")
    @Transactional(rollbackFor = Exception.class)
    @ApiOperation(value = "小程序支付回调（自营店支付回调）")
    synchronized
    public Map<String, String> jsapiNotify(HttpServletRequest request, HttpServletResponse response) {
        System.err.println("======================  进入支付回调  ======================");
        JSONObject bodyJson = getNotifyBodyJson(request);
        if (bodyJson == null) {
            return falseMsg(response);
        }
        if (lock.tryLock()) {
            try {
                // 解密resource中的通知数据
                String resource = bodyJson.getString("resource");
                JSONObject resourceJson = WechatPayValidator.decryptFromResource(resource, wechatPayConfig.getApiV3Key(), 2);
                log.info("  =================== 服务商小程序支付回调解密resource中的通知数据 ===================\n" + resourceJson);
                Integer trans = statusTrans(resourceJson.getString("trade_state"));
                Long oderId = resourceJson.getLong("attach");
                if (trans == 1 && oderId != null) {
                    //处理订单
                    Order order = orderService.selectOrderById(oderId);
                    order.setPayStatus(1);
                    order.setPayTime(DateUtils.getNowDate());
                    orderService.updateOrder(order);
                } else {
                    System.err.println("支付失败...");
                }

            } finally {
                lock.unlock();
            }
        }
        return trueMsg(response);
    }

    @PostMapping("/native")
    @Transactional(rollbackFor = Exception.class)
    @ApiOperation(value = "Native 支付回调（二维码支付回调）")
    synchronized
    public Map<String, String> nativeNotify(HttpServletRequest request, HttpServletResponse response) {
        System.err.println("======================  进入扫码回调  ======================");
        JSONObject bodyJson = getNotifyBodyJson(request);
        if (bodyJson == null) {
            return falseMsg(response);
        }
        if (lock.tryLock()) {
            try {
                // 解密resource中的通知数据
                String resource = bodyJson.getString("resource");
                JSONObject resourceJson = WechatPayValidator.decryptFromResource(resource, wechatPayConfig.getApiV3Key(), 2);
                log.info("  =================== 服务商小程序支付回调解密resource中的通知数据 ===================\n" + resourceJson);
                Integer trans = statusTrans(resourceJson.getString("trade_state"));
                Long oderId = resourceJson.getLong("attach");
                if (trans == 1 && oderId != null) {
                    //处理订单
                    Order order = orderService.selectOrderById(oderId);
                    order.setPayStatus(1);
                    order.setPayTime(DateUtils.getNowDate());
                    orderService.updateOrder(order);
                } else {
                    System.err.println("支付失败...");
                }

            } finally {
                lock.unlock();
            }
        }
        return trueMsg(response);
    }


    private String getNotifyXmlData(HttpServletRequest request) {
        try {
            BufferedReader reader = request.getReader();
            StringBuilder xmlData = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                xmlData.append(line);
            }
            return xmlData.toString();
        } catch (IOException e) {
            log.error("获取回调数据失败", e);
            return null;
        }
    }

    public static Map<String, String> parseXmlToMap(String xmlData) {
        Map<String, String> map = new HashMap<>();
        try {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document document = (Document) builder.parse(new InputSource(new StringReader(xmlData)));
            NodeList nodes = ((org.w3c.dom.Document) document).getElementsByTagName("*");
            for (int i = 0; i < nodes.getLength(); i++) {
                Node node = nodes.item(i);
                map.put(node.getNodeName(), node.getTextContent());
            }
        } catch (Exception e) {
            log.error("解析 XML 数据失败", e);
        }
        return map;
    }


    @PostMapping("/h5")
    @ApiOperation(value = "H5支付回调")
    public String h5Notify(@RequestBody String xmlData) {
        // 解析微信支付回调的XML数据
        Map<String, String> notifyMap = xmlToMap(xmlData);

        // 校验签名
        if (!checkWxPaySignature(notifyMap)) {
            return "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[签名失败]]></return_msg></xml>";
        }

        // 解析回调中的支付结果
        String resultCode = notifyMap.get("result_code");
        String outTradeNo = notifyMap.get("out_trade_no");
        String transactionId = notifyMap.get("transaction_id");
        String totalFee = notifyMap.get("total_fee");

        // 判断支付是否成功
        if ("SUCCESS".equals(resultCode)) {
            // 处理订单支付成功的逻辑
            // 可以在这里更新数据库状态、发送用户通知等
            log.info("支付成功，订单号: {}", outTradeNo);
            // 这里假设你有一个订单管理服务
//            orderService.updateOrderStatus(outTradeNo, OrderStatus.PAID);

            // 返回给微信服务器确认接收
            return "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
        } else {
            // 处理支付失败的情况
            log.error("支付失败，订单号: {}", outTradeNo);
            return "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[支付失败]]></return_msg></xml>";
        }
    }

    public boolean checkWxPaySignature(Map<String, String> notifyMap) {
        // 获取微信回调参数中的签名
        String sign = notifyMap.get("sign");
        // 获取不含签名的参数
        notifyMap.remove("sign");

        // 生成签名后的字符串
        String generatedSign = generateWxPaySignature(notifyMap);

        // 校验签名
        return sign.equals(generatedSign);
    }

    public String generateWxPaySignature(Map<String, String> params) {
        // 按照ASCII码顺序排序并拼接成key=value的格式
        StringBuilder stringBuilder = new StringBuilder();
        params.entrySet().stream()
                .filter(entry -> entry.getValue() != null && !"".equals(entry.getValue()))
                .sorted(Map.Entry.comparingByKey())
                .forEach(entry -> stringBuilder.append(entry.getKey()).append("=").append(entry.getValue()).append("&"));

        // 追加商户API密钥
        stringBuilder.append("key=").append(wechatPayConfig.getApiKey());

        // 生成MD5签名
        return DigestUtils.md5Hex(stringBuilder.toString()).toUpperCase();
    }

    public Map<String, String> xmlToMap(String xml) {
        // 将XML数据转为Map，可以使用常见的XML解析库，比如JAXB或简单的XML解析工具
        try {
            InputStream inputStream = new ByteArrayInputStream(xml.getBytes("UTF-8"));
            SAXReader reader = new SAXReader();
            Document document = reader.read(inputStream);
            Element root = document.getRootElement();
            Map<String, String> resultMap = new HashMap<>();
            for (Iterator<?> i = root.elementIterator(); i.hasNext(); ) {
                Element element = (Element) i.next();
                resultMap.put(element.getName(), element.getText());
            }
            return resultMap;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    private JSONObject getNotifyBodyJson(HttpServletRequest request) {
        //处理通知参数
        String body = HttpUtils.readData(request);
        log.info("===========微信回调参数===========\n" + body);
        log.info("微信回调参数：{}", body);
        // 转换为Map
        JSONObject jsonObject = JSONObject.parseObject(body);
        // 验证签名信息
        WechatPayValidator wechatPayValidator
                = new WechatPayValidator(commonPayController.getVerifier(), jsonObject.getString("id"), body);
        if (!wechatPayValidator.validate(request)) {
            log.error("通知验签失败");
            return null;
        }
        log.info("通知验签成功");
        return jsonObject;
    }


    @ApiOperation(value = "退款回调", notes = "退款回调")
    @PostMapping("/refundNotify")
    public Map<String, String> refundNotify(HttpServletRequest request, HttpServletResponse response) {
        // 处理通知参数
        JSONObject bodyJson = getNotifyBody(request);
        log.info("=========== 退款回调 =========== \n" + bodyJson);
        if (bodyJson == null) {
            return falseMsg(response);
        }


        log.warn("=========== 在对业务数据进行状态检查和处理之前，要采用数据锁进行并发控制，以避免函数重入造成的数据混乱 ===========");
//        if (lock.tryLock()) {
//            try {
//                String orderNumber = bodyJson.getString("order_number");
//                orderService.orderTK(orderNumber);
//            } finally {
//                //要主动释放锁
//                lock.unlock();
//            }
//        }
        //成功应答
        return trueMsg(response);
    }

    /**
     * 支付状态（ 1-支付成功 ）
     *
     * @param tradeState 微信返回支付状态码
     * @return 状态
     */
    private Integer statusTrans(String tradeState) {
        int payStatus;
        if ("SUCCESS".equals(tradeState)) {
            payStatus = 1;
        } else if ("NOTPAY".equals(tradeState)) {
            payStatus = 0;
        } else if ("REVOKED".equals(tradeState)) {
            payStatus = 4;
        } else if ("CLOSED".equals(tradeState)) {
            payStatus = 6;
        } else if ("PAYERROR".equals(tradeState)) {
            payStatus = 5;
        } else {
            payStatus = 8;
        }
        return payStatus;
    }

    private JSONObject getNotifyBody(HttpServletRequest request) {
        //处理通知参数
        String body = HttpUtils.readData(request);
        log.info("===========微信回调参数===========\n" + body);
        log.info("微信回调参数：{}", body);
        // 转换为Map
        JSONObject jsonObject = JSONObject.parseObject(body);
//        Map<String, Object> bodyMap = JSONObject.parseObject(body, new TypeReference<Map<String, Object>>() {
//        });
        // 验证签名信息
        WechatPayValidator wechatPayValidator
                = new WechatPayValidator(verifier, jsonObject.getString("id"), body);
        if (!wechatPayValidator.validate(request)) {

            log.error("通知验签失败");
            return null;
        }
        log.info("通知验签成功");
        return jsonObject;
    }

    private Map<String, String> falseMsg(HttpServletResponse response) {
        Map<String, String> resMap = new HashMap<>(8);
        //失败应答
        response.setStatus(500);
        resMap.put("code", "ERROR");
        resMap.put("message", "通知验签失败");
        return resMap;
    }

    private Map<String, String> trueMsg(HttpServletResponse response) {
        Map<String, String> resMap = new HashMap<>(8);
        //成功应答
        response.setStatus(200);
        resMap.put("code", "SUCCESS");
        resMap.put("message", "成功");
        return resMap;
    }

}
